iT邦幫忙

2026 iThome 鐵人賽

DAY 22
0
Software Development

從 Vibe Coding 到可維護專案:用 Hermes Agent 重讀 RoomRush Android 專題系列 第 22 篇

Day 22 | 選到教室之後,資料怎麼被查出來並修改?(下)

  • 分享至 

  • xImage
  •  

前言:管理者點選一間教室後,App 怎麼把它原本的資料找出來,最後又怎麼把修改結果存回去?

前一天,我們完成了選擇教室的這部分邏輯,今天一樣是繼續深入「教室細項設定」,但會著重在資料的更新。

當我們點擊了列表中的某一間教室時,會進入到這教室的詳細內容,裡面會顯示該教室是什麼類型和對應到是否可飲食的邏輯,管理者有權限可以更改其教室類型。

DetailSetupActivity.kt 會先接收上一頁(ClassroomAdapter.kt)傳來的 CLASSROOM_NAME ,教室類型會根據資料庫所設定的英文名稱,轉換成對應的中文顯示。


一開始我認為

一開始設計這個頁面時,有想過大概是怎麼樣的呈現方式,不過實際做完這個 UI 後,發現其實能互動的邏輯很少。

因為每當點擊列表中某個教室時,只能修改該教室的教室名稱而已,我們把是否可飲食的選項,設定成由教室類型自動決定,這樣寫可能少了一點彈性修改空間,但也是為了確保資料的一致性。

UI 畫面 操作流程
UI 畫面 操作流程

實際讀完後,DetailSetupActivity.kt 負責什麼

和 Hermes Agent 一起重讀教室詳細設定功能後,我了解了 DetailSetupActivity.kt 是教室詳細設定流程中,真正修改單一教室詳細資料的頁面。
它會接收上一頁傳來的 CLASSROOM_NAME,該頁面可以直接看到該教室資料,也會顯示教室名稱;主要可以查詢到的詳細內容是教室類型與是否可飲食,並讓管理者修改教室類型後儲存到 Room Database。

核心功能的三大技術重點:

1. 透過 SavedStateHandle 安全接收參數與觀察教室狀況

// 1. Factory 傳入 intent.extras,讓 ViewModel 透過 SavedStateHandle 取值
private val viewModel: ClassroomManageViewModel by viewModels {
		ClassroomManageViewModelFactory(
			(application as EmptyRoomFinderApp).appContainer.classroomScheduleRepository,
			this,
			intent.extras
		)
}
// 2. 觀察教室資料,查無資料時防呆退出
viewModel.classroomSchedule.observe(this) { schedule ->
		if (schedule != null) {
			roomNameTextView.text = schedule.classroom
			setupSpinners(schedule)
		} else {
				Toast.makeText(this, "錯誤:找不到教室資料", Toast.LENGTH_LONG).show()
				finish()
		}
}
  • 接收參數:ViewModel 可以透過 SavedStateHandle 取得上一頁 Intent 傳來的 CLASSROOM_NAME。
  • 狀態監聽:如果查到資料,就顯示教室名稱並設定 Spinner;如果查不到,提示錯誤並關閉頁面。

2. 教室類型與是否可飲食對應

// 1. 資料庫英文代碼 <-> UI 中文顯示
private fun mapClassroomTypeToDisplay(type: String?): String {
    return when (type) {
        "Normal" -> "一般教室"
        "Computer" -> "電腦教室"
        "Drawing" -> "製圖教室"
        "Lab" -> "實驗室"
        "MeetingRoom" -> "研討室"
        else -> "一般教室"
    }
}

// 2. 是否可飲食是由 classroomType 動態判定
val foodAllowedPosition = if (schedule.classroomType == "Normal") 0 else 1
foodAllowedSpinner.setSelection(foodAllowedPosition)
foodAllowedSpinner.isEnabled = false

  • 技術細節:教室類型由資料庫中的英文代碼轉成中文顯示。
  • 架構邏輯:是否可飲食目前不是獨立欄位,而是依據 classroomType == "Normal" 推導而來。一般教室顯示「是」,其他類型顯示「否」,且使用者不能直接修改。

3. 更新教室類型

fun updateClassroomType(newType: String) = viewModelScope.launch {
    val currentSchedule = classroomSchedule.value ?: return@launch
    // 透過 copy 只替換 classroomType 欄位,保留其他所有課表時段資料
    val updatedSchedule = currentSchedule.copy(classroomType = newType)
    repository.update(updatedSchedule)
    _updateResult.postValue(true)
}
  • 技術細節:ViewModel 會取得目前教室資料,用 copy(classroomType = newType) 產生更新後的物件,呼叫 Repository 更新資料庫,再顯示更新成功。

它接在哪一條流程上

查詢教室資料:

管理者點選教室
        ↓
ClassroomManageActivity
        ↓
取得教室名稱 CLASSROOM_NAME
        ↓
SavedStateHandle
「保存並提供教室名稱」
        ↓
ViewModel
「向 Repository 請求教室資料」
        ↓
Repository
「查詢指定教室」
        ↓
ClassroomSchedule
「取得該教室的課表資料」
        ↓
Activity
「顯示教室資料與類型」

修改教室資料:

管理者修改教室類型
        ↓
ClassroomManageActivity
「取得修改後的類型」
        ↓
ViewModel
「處理資料更新」
        ↓
Repository.update()
「傳遞更新請求」
        ↓
DAO.update()
「執行資料庫更新」
        ↓
Room Database
「儲存修改後的教室資料」

Hermes Agent 幫我檢查出的重點

DetailSetupActivity是教室詳細設定流程中真正修改單一教室詳細資料的頁面。它實際 class 名稱是 ClassroomManageActivity,layout 是 detail_setup.xml。

  • 上一頁 ClassroomAdapter 會透過 Intent 傳入 CLASSROOM_NAME,本頁的 ViewModel 透過 SavedStateHandle 取得這個教室名稱,並用 repository.getClassroomDetails(classroomName).asLiveData() 查詢該教室資料。
  • Activity observe 到資料後,顯示教室名稱,並用 setupSpinners() 設定教室類型與是否可飲食。
  • 教室類型會在英文代碼與中文顯示之間轉換,例如:Normal ↔ 一般教室。
  • 按下修改後,程式會確認是否儲存,將中文教室類型轉回英文代碼,呼叫 viewModel.updateClassroomType(newType),最後透過 repository.update() 更新 Room Database 中的 classroomType 欄位。

這個檔案帶出的維護觀察

  1. 命名不一致:繼先前的 DetailSetupActivity.kt 之後,這裡的 DetailChooseActivity.kt 同樣存在「檔名與內部 Class 名稱(ClassroomChooseManageActivity)對不上」的狀況。雖然不影響編譯,但在 IDE 進行全域搜尋或專案重構時,容易造成混亂。
  2. 「是否可飲食」缺乏獨立屬性:UI 介面上明確呈現了「是否可飲食」的標籤,但底層資料模型(Entity / Model)中卻根本沒有對應的欄位,而是由「教室類型」(如一般教室、電腦教室等等)在程式碼裡硬寫邏輯推導出來。

小結

讀到 DetailSetupActivity時,我看到了教室詳細設定流程真正修改資料的地方。

前一頁只是列出所有教室並傳出 CLASSROOM_NAME,這一頁則根據這個教室名稱查詢資料,顯示教室類型與是否可飲食,並讓管理者修改教室類型。

這裡的設計有一個值得注意的地方:畫面上雖然有「是否可飲食」,但它不是獨立欄位,而是由 classroomType 推導出來。只要教室類型是 Normal,就顯示可飲食;其他類型則顯示不可飲食。這種做法簡單,但未來如果需要更細緻的規則,例如某間一般教室不能飲食,就會遇到資料模型限制。

另外,這個檔案也延續了命名不一致的問題:檔案叫 DetailSetupActivity.kt,class 叫 ClassroomManageActivity,layout 叫 detail_setup.xml。這不影響執行,但對閱讀者來說會增加對照成本。

一句話總結這檔案:

ClassroomManageActivity 接收 CLASSROOM_NAME,查出該教室資料,讓管理者修改 classroomType,並透過 Repository.update() 寫回資料庫。


下一篇預告:如果我是管理者,我怎麼一次看懂所有教室狀態?

結束了「教室設定」這第二條管理者功能後,下一篇我們會進到最後最後一條支線-「教室狀態」。

下一個檔案我們會先讀 AllClassroomsActivity.kt ,從管理者主頁點擊「所有教室狀態」按鈕後,我們會看到所有教室狀態總覽頁如何顯示教室資訊,這畫面也提供了新增教室功能。


上一篇
Day 21 | 管理者要修改一間教室,首先要怎麼找到它?(上)
下一篇
Day 23 | 如果我是管理者,我怎麼一次看懂所有教室狀態?
系列文
從 Vibe Coding 到可維護專案:用 Hermes Agent 重讀 RoomRush Android 專題 共 23 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言